using System.IO;
using System.Web;
using System.Xml;
using System;

/*	-----------------------------------------------------------------------	
	Copyright:	umlungu consulting (pty) ltd
	Author:		Alan Benington	
	Started:	2007-05-01	
	Status:		release	
	Version:	0.0.1
	Build:		20070501
	License:	GNU General Public License
	-----------------------------------------------------------------------	*/
	
/*	-----------------------------------------------------------------------	
	Development Notes:
	==================
	20070805: Start (actually re-start becuase old class was redundant)
	-----------------------------------------------------------------------	*/
	
namespace umlungu.engineX.scorecardX {
	/// <summary>Description of the enumeration</summary>
	public enum x_identifier {
		/// <summary>identifier description</summary>
	    idOne = 1,
		/// <summary>identifier description</summary>
	    idTwo = 2,
		/// <summary>identifier description</summary>
	    idThree = 3,
		/// <summary>identifier description</summary>
		idFour = 4
	}
	/// <summary>
	/// Description of the x_score class.
	/// <para>This class deals with the calculation of scores in a scorecard</para>
	/// </summary>
	public class x_score {
		#region Invisible properties
		#endregion

		#region Constants
		private const string NODE = "score";
		private const string NODE_NAME = "name";
		private const string NODE_TYPE = "type";
		private const string NODE_VALUE = "value";
		private const string NODE_WEIGHT = "weight";
		private const string NODE_SCORE = "score";
		private const string TYPE_GROUP = "group";
		private const string TYPE_SET = "set";
		private const string SCORE_NULL = "uncalculated";
		private const string SCORE_ERROR = "unable to calculate";
		#endregion

		#region Error Constants
		private const string ERROR_SCORE_LOAD = "The scorecard has not been loaded.";
		private const string ERROR_SCORE_WEIGHT = "The score element '{0}' has not been weighted.";
		#endregion

		#region Visible properties
		private string property;
		/// <summary>Definiton of the property</summary>
		/// <value>Description of the value of the property</value>
		public string Property {
			get { return property; }
			set { property = value; }
		}
		private double value;
		/// <summary>The value of the score</summary>
		/// <value>An (double) value of a calculated score</value>
		public double Value {
			get { return value; }
			//set { value = value; }
		}
		private string score = SCORE_NULL;
		/// <summary>A score value</summary>
		/// <value>A string containg a representaion of the current score.</value>
		public string Score {
			get { return score; }
			//set { score = value; }
		}
		private XmlElement scorecard;
		/// <summary>A scorecard element (or scorecard fragment - eg a group)</summary>
		/// <value>An XmlElement containing the scorecard or part thereof</value>
		public XmlElement Scorecard {
			get { return scorecard; }
			set { scorecard = value; }
		}
		#endregion

		#region Constructors/Destructors
		/// <overloads>Constructor</overloads>
		/// <summary>Default constructor</summary>
		public x_score()  {
		}
		/// <summary>Constructor description</summary>
		/// <param name="ScoreName">The name of the score object</param>
		public x_score(XmlElement Score) {
		}
		#endregion

		#region Public methods
		/// <overloads>Loads an XmlElement (actually a node in a scorecard - an x_tree representation of a set of scores)</overloads>
		/// <summary>Loads an XmlElement</summary>
		public void Load(XmlElement ScoreElement) {
			scorecard = ScoreElement;
			reset();
		}
		/// <summary>Loads an XmlNode</summary>
		public void Load(XmlNode ScoreNode) {
			scorecard = ScoreNode as XmlElement;
			reset();
		}
		/// <summary>Loads an Xml string</summary>
		public void Load(string ScoreXml) {
			scorecard.InnerXml = ScoreXml;
			reset();
		}

		/// <overloads>Calculates the score value(s).</overloads>
		/// <summary>Assumes the score element is loaded</summary>
		public double Calculate() {
			value = 0;
			score = SCORE_ERROR;
			if (scorecard == null)
				throw new x_exception("ERROR_SCORE_LOAD", ERROR_SCORE_LOAD);
			value = Calculate(scorecard.SelectNodes(NODE));
			score = value.ToString();
			scorecard.SetAttribute(NODE_SCORE, score);
			return value;
		}
		/// <summary>Does calculation on nested scores</summary>
		public double Calculate(XmlNodeList scorelist) {
			double thisscore = 0;
			foreach (XmlNode scorenode in scorelist) {
				thisscore += Calculate(scorenode as XmlElement);
			}
			return thisscore;
		}
		/// <summary>Does calculation on a score node</summary>
		public double Calculate(XmlElement scoreelem) {
			double weight = 1.0, thisscore = 0;
			XmlNodeList scorelist = scoreelem.SelectNodes(NODE);

			// get weighting only for non-set elements
			if (scoreelem.GetAttribute(NODE_TYPE) != TYPE_SET) {
				string wght = scoreelem.GetAttribute(NODE_WEIGHT);
				if (wght == "")
					throw new x_exception("ERROR_SCORE_WEIGHT", String.Format(ERROR_SCORE_WEIGHT, scoreelem.GetAttribute(NODE_NAME)));
				weight = Convert.ToDouble(wght);
			}
			if (scorelist.Count == 0) {
				string val = scoreelem.GetAttribute(NODE_VALUE);
				if (val != "") {
					thisscore = Convert.ToDouble(val) * weight;
				}
				scoreelem.SetAttribute(NODE_SCORE, thisscore.ToString());
			} else {
				thisscore = Calculate(scorelist) * weight;
				scoreelem.SetAttribute(NODE_SCORE, thisscore.ToString());
			}
			return thisscore;
		}
		#endregion
		
		#region Protected methods
		#endregion
		
		#region Private methods
		private void reset() {
			score = SCORE_NULL;
		}
		#endregion
	}
}
